home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio
/
Ham Radio CD-ROM (Emerald Software) (1995).ISO
/
cw
/
robocopy
/
robo.c
< prev
next >
Wrap
Text File
|
1990-09-21
|
30KB
|
979 lines
/* CW monitor uses RI signal on COM1 (pin 8 of DB25 pin 9 on a DB9) */
/* input stimulus. A space = +5v, mark = 0v works with RS 232 systems */
/* CTS and DSR must be tied to space level (5v) for port to operate */
/* CTS is 5/DB25 8/DB9 DSR is 6/DB25 6/DB9 */
#include <stdio.h>
#include <bios.h>
#include <dos.h>
#include <graphics.h>
#include <conio.h>
#include <sys\timeb.h>
#include <sys\types.h>
#define SIZE 32
#define PRINT_CHAR 0
#define PRINT_SPACE 1
#define PRINT_OVR 2
#define FLUSH 1
#define UPDATE 2
#define MARK 0x80
#define SPACE 0
#define RESET 0
#define SET 1
#define ON 1
#define OFF 0
#define DIT 1
#define DAH 2
#define NULL 0
#define HIGH 1
#define LOW 0
#define START 0
#define STOP 2
#define FINISH 1
#define READ 1
#define NORMAL 7
#define UP 6
#define DOWN 7
#define BELL 7
#define TICK 1
#define NOTICK 0
union REGS regs;
struct WINDOW {
unsigned char tlrow;
unsigned char tlcol;
unsigned char brrow;
unsigned char brcol;
unsigned char attr;
};
struct WINDOW screen = {11,0,19,79,NORMAL};
struct WINDOW spadscrn = {21,0,24,79,NORMAL};
int space_msec, mark_msec, temp, old_vmode, space_flag, row, col,
loop, buffer[9], *bufptr, word_flag, word_mul, char_mul, prikey,
char_flag, mark_count, init_flag, spad_flag, spad_row, spad_col,
mark_stack[SIZE], *mark_ptr, md_stack[SIZE], *md_ptr, fence, *temp_ptr,
sp_buffer[8], *sp_ptr, sp_count, filter_co, write_flag, write_char,
tempkey, e_col, e_row, key, sec_char, dit_msec, skew_count, delta_sec,
delta_msec, speed, wpm_flag, teach;
long avg, md_avg, md_val;
/* func declarations */
void char_print(int c_flag);
int read_port(int next_state);
void space_func(void);
void mark_func(void);
int stop_watch(void);
void entry_func(void);
void write(char *strptr);
void scroll(struct WINDOW window, int lines, int dir);
void spot_print(int attr, val);
void filter_print(int attr);
void auto_term(void);
void wpm_func(void);
void char_out(void);
void diagnostic(void);
/* initialize program */
/* set up nominal operation parameters */
main()
{
teach = OFF;
init_flag = SET;
spad_flag = OFF;
row = 11;
col = 0;
spad_row = 21;
spad_col = 0;
prikey = 0;
write_flag = RESET;
fence = 100;
filter_co = 32;
char_mul =25;
word_mul = 67;
skew_count = 0;
for(temp_ptr = &mark_stack[0]; temp_ptr <= &mark_stack[SIZE -1]; temp_ptr++)
*temp_ptr = 100;
for(temp_ptr = &md_stack[0]; temp_ptr <= &md_stack[SIZE -1]; temp_ptr++)
*temp_ptr = 0;
mark_ptr = &mark_stack[0];
md_ptr = &md_stack[0];
sp_ptr = &sp_buffer[0];
sp_count = 0;
bufptr = &buffer[0];
for(loop = 0; loop < 8; loop++)
{*bufptr = NULL;
bufptr++;
}
mark_count = 0;
bufptr = &buffer[0];
/* set up com1 as 4800bd 7 bits 1 stop, 1 start, no parity */
/* fakes a real good 2 ms time clock */
regs.x.dx = 0;
regs.h.ah = 0;
regs.h.al = 0xC2;
int86(0x14,®s,®s);
/* set up entry and working screens */
/* code displayed on screen 0 */
old_vmode = getvmode();
setvmode(3);
setcolor(9,3);
setapage(0);
clrscrn();
poscurs(0,7);
write("ROBO-COPy 73 Magazine Automated CW Copier by WB9DYI/Mike Hansen");
poscurs(2,7);
write("Change a copy parameter by typing it's first letter (L,W,F); then ");
poscurs(3,7);
write("modify value using +/- keys. Terminate change by pressing Enter key.");
poscurs(4,7);
write("Type H for help; Q exits to DOS; R resets copy parameters. Space bar");
poscurs(5,7);
write("toggles scratch pad area on/off. Type S to clear scratch pad area,");
poscurs(6,7);
write("C to clear copy area. M toggles between normal and teach modes.");
poscurs(8,2);
write("Letter Timing dits. Word Timing dits. Mode Filter");
poscurs(10,0);
writechs('_',0x07,80);
poscurs(10,33);
write("WPM = ");
poscurs(20,0);
writechs('-',0x07,80);
poscurs(20,30);
write("Scratch Pad ");
setvpage(0); /* copy starts at row 10 col 0 */
/* v_page 0 cleared for copy */
/* set up help screen, v_ page 1 */
setapage(1);
setcolor(9,3);
poscurs(0,9);
write("Intended for private use only. All commercial rights reserved.");
poscurs(2,27);
write("ROBO-COPy HELP SCREEN");
poscurs(3,10);
write("Decrease letter timing when the over run error ");
poscurs(4,10);
write("symbol # ocurrs frequently.");
poscurs(6,10);
write("Increase letter timing when longer characters");
poscurs(7,10);
write("break-up into short letters; example SOS = EEETTTEEE.");
poscurs(9,10);
write("If wordsruntogetherlikethis...decrease word timing.");
poscurs(11,10);
write("If letters a r e separated in words...increase word timing.");
poscurs(13,10);
write("A sampling filter helps reduce the effects of QRN. It has three ");
poscurs(14,10);
write("settings, LOW, MEDIUM and HI. LOW filtering is best for");
poscurs(15,10);
write("high speed reception, but is more susceptible to noise.");
poscurs(16,10);
write("When receiving noisy signals, HI filtering works to eliminate the");
poscurs(17,10);
write("interference but reduces copy speed to less than 30-35 WPM.");
poscurs(19,10);
write("Unrecognized characters and errors are displayed as *.");
poscurs(20,10);
write("Command characters like are displayed in reverse video.");
poscurs(20,34);
writechs('S',0x70,1);
poscurs(20,35);
writechs('K',0x70,1);
poscurs(21,10);
write("Keep important QSO data like call signs, etc. in Scratch Pad");
poscurs(22,10);
write("by toggling area ON/OFF with Space bar. Type S to clear the area.");
poscurs(24,13);
write("Press space bar for more HELP, Press Enter key to exit HELP.");
/* screen 1 finished */
setapage(2);
poscurs(0,23);
write("Recommend receiver operation for ROBO-COPy");
poscurs(2,10);
write("The ROBO-COPy interface can be connected in parallel with either");
poscurs(3,10);
write("the speaker or low-impedance headphone outputs. The added load is");
poscurs(4,10);
write("about 330 ohms, and should have no noticeable effect on the quality");
poscurs(5,10);
write("or volume of the audio output. The output of the ROBO-COPy ");
poscurs(6,10);
write("interface should be connected to the COM1 port of the P.C..");
poscurs(8,30);
write("ROBO-COPying a CW station");
poscurs(10,20);
write("AGC = FAST, Noise Blanker = ON, CW Filter = ON");
poscurs(11,10);
write("1. Tune station as you would normally do for cw reception.");
poscurs(12,10);
write("2. Reduce audio and RF gain to the MINIMUM needed for solid copy.");
poscurs(13,10);
write("3. Increase audio gain until LED on ROBO-COPy interface flashes");
poscurs(14,10);
write(" bright, distinct dits and dahs.");
poscurs(24,25);
write("Press any key to exit HELP.");
setapage(0);
setvpage(0);
do
{if(read_port(MARK) != SPACE)
mark_func();
space_func();
}while (0 == 0);
}/* end of main brace */
/* start of program */
void space_func(void)
{
word_flag = START;
char_flag = START; /* start assembling character */
space_msec = 0;
while(read_port(MARK) == SPACE)
{ if(stop_watch() == TICK)
space_msec = space_msec + 2;
/* check keyboard */
key = getkey();
if(key != EOF || init_flag == SET)
entry_func();
/* background task of displaying data */
if(write_flag == SET) /* write to screen */
{ char_out();
if(sec_char != 0)
{write_char = sec_char;
char_out();
}
}
if(teach == OFF)
{
dit_msec = avg/2;
if(space_msec > (char_mul * dit_msec)/10 && char_flag == START &&
mark_count > 0)
{char_print(PRINT_CHAR);
char_flag = FINISH;
wpm_func(); /* outputwpm */
}
if(space_msec > (word_mul * dit_msec)/10 && word_flag == START)
{word_flag = FINISH;
char_print(PRINT_SPACE);
}
}
} /* done with background house keeping now back to biz */
/* process space */
if(teach == ON)
{
dit_msec = avg/2;
if(space_msec > (char_mul * dit_msec)/10 && char_flag == START &&
mark_count > 0)
{char_print(PRINT_CHAR);
char_flag = FINISH;
wpm_func(); /* outputwpm */
if(write_flag == SET) /* write to screen */
{char_out();
if(sec_char != 0)
{write_char = sec_char;
char_out();
}
}
}
if(space_msec > (word_mul * dit_msec)/10 && word_flag == START)
{word_flag = FINISH;
char_print(PRINT_SPACE);
char_out();
}
}
return; /* return on mark */
} /* end of space_func */
void mark_func(void)
{
/* MARK detected in space_func is timed here */
sp_count++;
if(sp_count > 7)
{sp_count = 0;
sp_ptr = &sp_buffer[0];
}
*sp_ptr = space_msec;
sp_ptr++;
mark_msec = 2; /* add 2 for initial loop-compensates for sampling time */
/* check for end of mark */
while(read_port(SPACE) != SPACE)
{if(stop_watch() == TICK)
{if(mark_msec < 1000)
mark_msec = mark_msec + 2;
}
}
/* is mark within range ? */
if(mark_msec < 10 )
return;
mark_count++;
if(mark_msec > fence)
*bufptr = DAH;
else *bufptr = DIT;
bufptr++;
if(bufptr > &buffer[8])
char_print(PRINT_OVR);
/* calculate latest mean deviation and store on stack */
md_ptr++;
if(md_ptr > &md_stack[SIZE -1])
md_ptr = &md_stack[0];
*md_ptr = mark_msec - avg;
/* calculate new average of mean deviation */
md_avg = 0;
for(temp_ptr = &md_stack[0]; temp_ptr <= &md_stack[SIZE -1]; temp_ptr++)
md_avg = md_avg + *temp_ptr;
md_avg = md_avg/SIZE;
/* generate absolute value of mean deviation times 4 */
md_val = 4 * md_avg;
if(md_val < 0)
md_val = -1 * md_val;
/* avoid corrupting average with skew due to repetition */
if(mark_msec < *mark_ptr + (*mark_ptr/8) ||
mark_msec > *mark_ptr - (*mark_ptr/8))
skew_count++;
else skew_count = 0;
if(skew_count < 4 || md_val > avg)
{
/* load mark_stack with last mark */
mark_ptr++;
if(mark_ptr > &mark_stack[SIZE -1])
mark_ptr = &mark_stack[0];
*mark_ptr = mark_msec;
/* calculate new average */
avg = 0;
for(temp_ptr = &mark_stack[0]; temp_ptr <= &mark_stack[SIZE -1]; temp_ptr++)
avg = avg + *temp_ptr;
avg = avg/SIZE;
/* calculate new fence point */
fence = avg + md_avg;
}
return;
} /* end of mark_func */
void char_print(int c_flag)
{ int temp, exp, loop, sum;
char letter[] ="ETIANMSURWDKGOHVF*L*PJBXCYZQ";
char alpha;
char *letter_ptr, *number_ptr;
sec_char = 0; /* reset special command character value */
write_flag = SET;
if(c_flag == PRINT_OVR)
write_char = '#';
if(c_flag == PRINT_SPACE)
write_char = ' ';
else{
bufptr = &buffer[7];
sum = 0;
exp = 128;
for(loop = 0; loop < 8; loop++)
{temp = *bufptr;
while(*bufptr == 0)
{exp = exp/2;
bufptr--;
}
}
bufptr = &buffer[0];
while(exp != 0)
{ sum = sum + ((*bufptr) * exp);
exp = exp/2;
bufptr++;
}
if(mark_count == 0)
return;
if((mark_count <= 4) && (sum < 29))
{letter_ptr = &letter[0];
alpha = *(letter_ptr + (sum - 1));
write_char = alpha;
}
if(mark_count== 5)
{switch(sum){
case 62: write_char = '0';
break;
case 61: write_char = '9';
break;
case 59: write_char = '8';
break;
case 55: write_char = '7';
break;
case 47: write_char = '6';
break;
case 31: write_char = '5';
break;
case 32: write_char = '4';
break;
case 34: write_char = '3';
break;
case 38: write_char = '2';
break;
case 46: write_char = '1';
break;
case 33: write_char = 'S';
sec_char = 'N';
break;
case 41: write_char = 'A';
sec_char = 'R';
break;
case 39: write_char = 'A';
sec_char = 'S';
break;
case 52: write_char = 'K';
sec_char = 'A';
break;
case 48: write_char = '=';
break;
case 49: write_char = '/';
break;
case 53: write_char = '(';
break;
default: write_char = '*';
}
}
if(mark_count == 6)
{switch(sum)
{case 68: write_char = 'S';
sec_char = 'K';
break;
case 75: write_char = '?';
break;
case 84: write_char = '.';
break;
case 114: write_char = ',';
break;
case 93: write_char = ''';
break;
case 76: write_char = 'I';
sec_char = 'Q';
break;
case 83: write_char = 'A';
sec_char = 'L';
break;
case 81: write_char = '"';
break;
case 105: write_char = ';';
break;
case 96: write_char = '-';
break;
case 108: write_char = ')';
break;
case 119: write_char = ':';
break;
default: write_char = '*';
}
}
if(mark_count == 7)
{if(sum == 136)
write_char = '$';
else write_char = '*';
}
if(mark_count == 8)
{if(sum == 255)
{write_char = 'H';
sec_char = 'H';
}
else write_char = '*';
}
}/* end of else */
for(bufptr = &buffer[0]; bufptr <= &buffer[7]; bufptr++)
*bufptr = 0; /* clear DIT/DAH buffer */
bufptr = &buffer[0];
mark_count = 0;
return;
} /* end of char_print function */
int read_port(int next_state)
{int fcount, temp, delay;
/* read_port has a sampling filter built in. There must be */
/* filter_co times the next state before a transistion is reported via */
/* the returned value */
fcount = 0;
do
{fcount++;
regs.x.dx = 0;
regs.h.ah = 3;
int86(0x14,®s,®s);
temp = regs.h.al & 0x80;
for(delay = 0; delay < 16; delay++)
;
}while(temp == next_state && fcount < filter_co);
if(fcount >= filter_co)
temp = next_state; /* successfully completed filter */
else
{if(next_state == MARK) /* noisy signal returns current state */
temp = SPACE;
else temp = MARK;
}
return(temp);
}
/* stop_watch generates a 2 ms wait */
int stop_watch(void)
{int loop;
regs.x.dx = 0;
regs.h.ah = 3;
int86(0x14,®s,®s);
if(regs.h.ah & 0x40 == 0)
return(NOTICK); /* xmit buffer not empty */
regs.x.dx = 0; /* xmit buffer empty, fill it */
regs.h.ah = 1;
regs.h.al = ' ';
int86(0x14,®s,®s);
return(TICK);
}
void write(char *strptr)
{int row, col;
row = cursrow();
col = curscol();
while(*strptr != NULL)
{writechs(*strptr, 0x07,1);
strptr++;
col++;
poscurs(row,col);
}
return;
}
void entry_func(void)
{
cursoff();
e_row = 8; /* all parameters are on row 8 */
tempkey = key & 0x00FF; /* makes sure key is upper case */
if(tempkey == '~')
{diagnostic();
return;
}
if(tempkey > 0x60)
tempkey = tempkey - 32;
if(init_flag == SET)
{init_flag = RESET;
tempkey = 'R';
}
switch(tempkey)
{
case 'C': scroll(screen, 0 , UP); /* clear scratch pad screen */
row = 11;
col = 0;
break;
case 'F': if(prikey != 0)
auto_term();
filter_print(0x70);
prikey = tempkey;
break;
case 'H': setvpage(1); /* Help just changes screens */
temp = getch();
if(temp == ' ')
{setvpage(2);
temp = getch();
}
setvpage(0);
break;
case 'L': if(prikey != 0)
auto_term();
e_col = 16; /* highlite letter selection */
spot_print(0x70, char_mul);
prikey = tempkey;
break;
case 'W': if(prikey != 0)
auto_term();
e_col = 39;
spot_print(0x70, word_mul);
prikey = tempkey;
break;
case ' ': if(spad_flag == ON) /* toggle scratch pad */
{spad_flag = OFF;
poscurs(20,42);
writechs('O', 0x07,1);
poscurs(20,43);
writechs('F',0x07,2);
}
else{
spad_flag = ON;
poscurs(spad_row, spad_col);
writechs('|', 0x07, 1);
spad_col++;
if(spad_col > 79)
{spad_col = 0;
spad_row++;
if(spad_row > 24)
{spad_row = 24;
scroll(spadscrn, 1,UP);
}
}
poscurs(20,42);
writechs('O',0x70,1);
poscurs(20,43);
writechs('N',0x70,1);
poscurs(20,44);
writechs(' ',0x07,1);
}
break;
case '+': if(prikey != 0)
{if(prikey == 'L')
{char_mul++;
if(char_mul > 45)
char_mul = 45;
e_col = 16;
spot_print(0x70, char_mul);
}
if(prikey == 'W')
{word_mul = word_mul + 1;
if(word_mul > 95)
word_mul = 95;
e_col = 39;
spot_print(0x70, word_mul);
}
if(prikey == 'F')
{filter_co = filter_co + filter_co;
if(filter_co > 64)
filter_co = 16;
filter_print(0x70);
}
}
else putch(BELL);
break;
case '-': if(prikey != 0)
{if(prikey == 'L')
{char_mul--;
if(char_mul < 5)
char_mul = 5;
e_col = 16;
spot_print(0x70, char_mul);
}
if(prikey == 'W')
{word_mul = word_mul - 1;
if(word_mul < 25)
word_mul = 25;
e_col = 39;
spot_print(0x70, word_mul);
}
if(prikey == 'F')
{filter_co = filter_co/2;
if(filter_co < 16)
filter_co = 64;
filter_print(0x70);
}
}
else putch(BELL);
break;
case 'R': char_mul = 17;
word_mul = 67;
filter_co = 32;
prikey = 0;
e_col = 16;
poscurs(e_row, e_col);
spot_print(0x07, char_mul);
e_col = 39;
poscurs(e_row, e_col);
spot_print(0x07, word_mul);
e_col = 69;
poscurs(e_row, e_col);
filter_print(0x07);
spad_flag = OFF;
poscurs(20,42);
writechs('O', 0x07,1);
poscurs(20,43);
writechs('F',0x07,2);
poscurs(8,55);
if(teach == ON)
printf("Teach ");
else printf("Normal");
break;
case 'S': scroll(spadscrn, 0 , UP);
spad_col = 0;
spad_row = 21;
break;
case 0x0D: prikey = 0;
e_col = 16;
poscurs(e_row, e_col);
spot_print(0x07, char_mul);
e_col = 39;
poscurs(e_row, e_col);
spot_print(0x07, word_mul);
e_col = 69;
poscurs(e_row, e_col);
filter_print(0x07);
break;
case 'Q':setvmode(old_vmode);
regs.x.dx = 0; /* Restore COM1 */
regs.h.ah = 0;
regs.h.al = 0xE3;
/* re-set to 9600 bd 1 Start, 1 stop, no parity, 8 bits */
int86(0x14,®s,®s);
curson();
exit(0);
case 'M': poscurs(8,55);
if(teach == ON)
{teach = OFF;
printf("Normal");
}
else{
teach = ON;
printf("Teach ");
}
break;
default: putch(BELL);
break;
}/* end of switch*/
poscurs(row,col);
curson();
return; /* return from entry_func */
} /* end of entry_func */
void spot_print(int attr, val)
{int tens, ones;
tens = val/10;
ones = val - (10*tens);
poscurs(e_row, e_col);
if(tens == 0)
tens = -0x10; /* fake a space */
writechs(tens + 0x30, attr, 1);
e_col++;
poscurs(e_row, e_col);
writechs('.', attr, 1);
e_col++;
poscurs(e_row, e_col);
writechs(ones + 0x30, attr, 1);
return;
}
void filter_print(int attr)
{
e_col = 71;
if(filter_co == 16)
{poscurs(e_row, e_col);
writechs('L', attr, 1);
e_col++;
poscurs(e_row, e_col);
writechs('O', attr, 1);
e_col++;
poscurs(e_row, e_col);
writechs('W', attr, 1);
}
if(filter_co == 32)
{poscurs(e_row, e_col);
writechs('M', attr, 1);
e_col++;
poscurs(e_row, e_col);
writechs('E', attr, 1);
e_col++;
poscurs(e_row, e_col);
writechs('D', attr, 1);
}
if(filter_co == 64)
{poscurs(e_row, e_col);
writechs('H', attr, 1);
e_col++;
poscurs(e_row, e_col);
writechs('I', attr, 1);
e_col++;
poscurs(e_row, e_col);
writechs(' ', attr, 1);
}
return;
} /* end of filter_print*/
void scroll(struct WINDOW window, int lines, int dir)
{
regs.h.ah = dir;
regs.h.al = lines;
regs.h.ch = window.tlrow;
regs.h.cl = window.tlcol;
regs.h.dh = window.brrow;
regs.h.dl = window.brcol;
regs.h.bh = window.attr;
int86(0x10,®s,®s);
return;
}
void auto_term(void)
{
e_row = 8;
e_col = 16;
spot_print(0x07, char_mul);
e_col = 39;
spot_print(0x07, word_mul);
filter_print(0x07);
return;
}
void wpm_func(void)
{int wpm, huns, tens;
if(avg <= 0)
{poscurs(10, 39);
writechs('*',0x07,3);
return;
}
wpm = 2400/avg;
huns = wpm/100;
wpm = wpm - (huns * 100);
tens = wpm/10;
wpm = wpm - (tens * 10);
poscurs(10,39);
if(huns == 0)
huns = -0x10;
writechs(huns + 0x30, 0x07, 1);
poscurs(10,40);
if(tens == 0 && huns == -0x10 )
tens = -0x10; /* fake a space */
writechs(tens + 0x30, 0x07,1);
poscurs(10,41);
writechs(wpm + 0x30, 0x07,1);
return;
}
void char_out(void)
{
int attr;
write_flag = RESET;
attr = 0x07;
if(sec_char != 0)
attr = 0x70;
poscurs(row, col);
writechs(write_char, attr, 1);
col++;
if(col > 79)
{col = 0;
if(row < 19)
row++;
else
scroll(screen, 1, UP);
}
if(spad_flag == ON)
{spad_col++;
if(spad_col > 79)
{spad_col = 0;
if(spad_row < 24)
spad_row++;
else scroll(spadscrn, 1, UP);
}
poscurs(spad_row, spad_col);
writechs(write_char, attr, 1);
}
poscurs(row,col);
return;
}
void diagnostic(void)
{int count, *ptr;
scroll(screen, 0, UP);
poscurs(11,0);
printf("Average mark milliseconds %li\n",avg);
printf("Last 8 mark times in milliseconds\n");
ptr = mark_ptr;
for(count = 0; count < 8 ; count++)
{printf("%i ", *ptr);
ptr--;
if(ptr < &mark_stack[0])
ptr = &mark_stack[SIZE -1];
}
printf("\n");
printf("Average deviation from mean milliseconds %li\n",md_avg);
printf("Last 8 mean deviation times in milliseconds\n");
ptr = md_ptr;
for(count = 0; count <8 ; count++)
{printf("%i ", *ptr);
ptr--;
if(ptr < &md_stack[0])
ptr = &md_stack[SIZE - 1];
}
printf("\n");
printf("Last 8 space times in milliseconds\n");
ptr = sp_ptr;
for(count = 0; count < 8 ; count++)
{printf("%i ", *ptr);
ptr--;
if(ptr < &sp_buffer[0])
ptr = &sp_buffer[7];
}
printf("\n");
count = getch();
scroll(screen,0,UP);
row = 11;
col = 0;
return;
}